﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using System.Data.SqlClient;

namespace SQLDeployTool
{
    class Program
    {

        public static void Main(string[] args)
        {
            Console.Clear();
            Console.ForegroundColor = ConsoleColor.DarkYellow;
            Console.WriteLine("Version: " + GetProductVersion() + "\n");
            Console.ResetColor();
            
                        
            string dbServer = null;
            string dbName = null;
            if (args.Length == 0)
            {
                Console.Write("Enter the database server:  ");
                dbServer = Console.ReadLine();
                Console.Write("Enter the database name: ");
                dbName = Console.ReadLine();

                if (isReadyToDeploy(dbName, dbServer))
                {
                    processFiles(getFiles(), dbServer, dbName);
                }
            }
            else
            {
                // grab the command line arguments
                for (int i = 0; i < args.Length; i++)
                {
                    if (args[i].ToUpper() == "-S")
                    {
                        try
                        {
                            dbServer = args[i + 1];
                        }
                        catch 
                        {
                            Console.WriteLine("Error! Your parameters are incorrect.");
                        }
                        
                    }
                    if (args[i].ToUpper() == "-D")
                    {
                        try
                        {
                            dbName = args[i + 1];
                        }
                        catch 
                        {
                            Console.WriteLine("Error! Your parameters are incorrect.");

                        }
                        
                    }
 
                }

                if (isReadyToDeploy(dbName, dbServer))
                {
                    processFiles(getFiles(), dbServer, dbName);
                }
            }
            
        }

        /// <summary>
        /// If dbNull and dbName have values and you answered yes to the deploy question, return true.
        /// </summary>
        /// <param name="dbName"></param>
        /// <param name="dbServer"></param>
        /// <returns></returns>
        public static bool isReadyToDeploy(string dbName, string dbServer)
        {
            if (string.IsNullOrEmpty(dbName) || string.IsNullOrEmpty(dbServer))
            {
                Console.WriteLine("Error! Either the database name or the server name is null.");
                return false;
            }
            Console.WriteLine("Type YES to to deploy changes to the {0} database on {1}.", dbName, dbServer);
            string answer = Console.ReadLine();
            if (answer == "YES")
            {
                return true;
            }
            else
            {
                return false;
            }

        }


        /// <summary>
        /// Reads the file version info from the AssemblyInfo.cs file to display when needed
        /// </summary>
        /// <returns></returns>
        protected static string GetProductVersion()
        {
            Assembly asm = Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(asm.Location);
            return fvi.FileVersion;
        }

        
        /// <summary>
        /// Execute the .sql files using the SQLCMD.exe
        /// </summary>
        /// <param name="files"></param>
        /// <param name="dbServer"></param>
        protected static void processFiles(List<string> files, string dbServer, string dbName)
        {
            System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
            System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo("CMD.exe");
           
            // Build the log file name
            StringBuilder logfile = new StringBuilder();
            
            logfile.Append(DateTime.Now.Month.ToString());
            logfile.Append("-");
            logfile.Append(DateTime.Now.Day.ToString());
            logfile.Append("-");
            logfile.Append(DateTime.Now.Year.ToString());
            logfile.Append("_");
            logfile.Append(DateTime.Now.Hour.ToString());
            logfile.Append(".");
            logfile.Append(DateTime.Now.Minute.ToString());
            logfile.Append(".");
            logfile.Append(DateTime.Now.Second.ToString());
            logfile.Append(".log");

            //string s;
            

            info.RedirectStandardInput = true;
            info.RedirectStandardOutput = true;
            info.UseShellExecute = false;
            info.CreateNoWindow = true;
            
            myProcess.StartInfo = info;
            myProcess.Start();

            System.IO.StreamWriter SW = myProcess.StandardInput;
            System.IO.StreamReader SR = myProcess.StandardOutput;

            SW.AutoFlush = true;

            SW.WriteLine("@echo *******Start processing - {0} >> {1}", DateTime.Now.ToString(), logfile);
            SW.WriteLine("@echo. >> {0}", logfile);



            foreach (string file in files)
            {
                
                try
                {
                    Console.WriteLine("Processing {0}", file);

                    if (isFileReady(logfile.ToString())) { SW.WriteLine("@echo **** {0} >> {1}", file, logfile); };
                    
                    if (isFileReady(logfile.ToString())) { SW.WriteLine(@"sqlcmd -E -S {1} -d {3} -i {0} >> {2}", file, dbServer, logfile.ToString(),dbName); }
                    
                    if (isFileReady(logfile.ToString())) { SW.WriteLine("@echo. >> {0}", logfile); }

                    SR.Dispose();
                   

                }

                catch
                {
                    throw;
                }

            }

            SW.WriteLine("@echo *******End processing - {0} >> {1}", DateTime.Now.ToString(), logfile);

            SW.WriteLine(logfile.ToString());
            SW.WriteLine("exit");
            
            SW.Close();
            SR.Close();


            

        }
       
        
        /// <summary>
        /// Check to see if the file is ready to be written to again or if it's already open.
        /// If it's open, wait for 500ms and try again.
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        protected static bool isFileReady(string file)
        {
            FileStream fs = null;
            FileInfo f = new FileInfo(file);
            bool isReady = false;

            

            while (!isReady)
            {
                try
                {
                    fs = f.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                    isReady = true;
                }
                catch
                {
                    System.Threading.Thread.Sleep(500);
                }
                finally 
                {
                    if (fs != null)
                    {
                        fs.Close();
                    }
                }
                
            }

            return isReady;
                    
        }
 
        /// <summary>
        /// Get a list of files in the directory (filtered by .sql extension)
        /// </summary>
        /// <returns></returns>
        protected static List<string> getFiles()
        {
            System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(".");
            List<string> files = new List<string>();
            
            
            // Read the current directory for .sql files
            foreach (System.IO.FileInfo f in di.GetFiles("*.sql"))
            {
                files.Add(f.Name);
            }

            return files;
            
        }
    }
}
